<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        /**
         *  axios 是⼀个轻量的 HTTP 客户端
            基于 XMLHttpRequest 服务来执⾏ HTTP 请求，⽀持丰富的配置，⽀持 Promise ，⽀持浏览
            器端和 Node.js 端。⾃ Vue 2.0起，尤⼤宣布取消对 vue-resource 的官⽅推荐，转⽽推荐 a
            xios 。现在 axios 已经成为⼤部分 Vue 开发者的⾸选

            import axios from 'axios'
            axios({ 
                url:'xxx', // 设置请求的地址
                method:"GET", // 设置请求⽅法
                params:{ // get请求使⽤params进⾏参数凭借,如果是post请求⽤data
                type: '',
                page: 1
                }
                }).then(res => { 
                // res为后端返回的数据
                console.log(res); 
            })
                
                function getUserAccount() {
                    return axios.get('/user/12345');
                }
                function getUserPermissions() {
                    return axios.get('/user/12345/permissions');
                }
                axios.all([getUserAccount(), getUserPermissions()])
                .then(axios.spread(function (res1, res2) {
                // res1第⼀个请求的返回的内容，res2第⼆个请求返回的内容
                // 两个请求都执⾏完成才会执⾏
                }));


                axios 的 API 很友好，你完全可以很轻松地在项⽬中直接使⽤。
                不过随着项⽬规模增⼤，如果每发起⼀次 HTTP 请求，就要把这些⽐如设置超时时间、设置请求头、根
                据项⽬环境判断使⽤哪个请求地址、错误处理等等操作，都需要写⼀遍
                这种重复劳动不仅浪费时间，⽽且让代码变得冗余不堪，难以维护。为了提⾼我们的代码质量，我们应
                该在项⽬中⼆次封装⼀下 axios 再使⽤

                如果每次请求都这样
                axios('http://localhost:3000/data', {
                    // 配置代码
                    method: 'GET',
                    timeout: 1000,
                    withCredentials: true,
                    headers: {
                    'Content-Type': 'application/json',
                    Authorization: 'xxx',
                    },
                    transformRequest: [function (data, headers) {
                    return data;
                    }],
                    // 其他请求配置...
                    })
                    .then((data) => {
                    // todo: 真正业务逻辑代码
                    console.log(data);
                    }, (err) => {
                    // 错误处理代码 
                    if (err.response.status === 401) {
                    // handle authorization error
                    }
                    if (err.response.status === 403) {
                    // handle server forbidden error
                    }
                    // 其他错误处理.....
                    console.log(err);
                    });
            封装: 

            /**axios封装
             * 请求拦截、相应拦截、错误统一处理
             */
            import axios from 'axios';import QS from 'qs';
            import { Toast } from 'vant';
            import store from '../store/index'
            
            // 环境的切换
            if (process.env.NODE_ENV == 'development') {    
                axios.defaults.baseURL = '/api';
            } else if (process.env.NODE_ENV == 'debug') {    
                axios.defaults.baseURL = '';
            } else if (process.env.NODE_ENV == 'production') {    
                axios.defaults.baseURL = 'http://api.123dailu.com/';
            }
            
            // 请求超时时间
            axios.defaults.timeout = 10000;
            
            // post请求头
            axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
            
            // 请求拦截器
            axios.interceptors.request.use(    
                config => {
                    // 每次发送请求之前判断是否存在token，如果存在，则统一在http请求的header都加上token，不用每次请求都手动添加了
                    // 即使本地存在token，也有可能token是过期的，所以在响应拦截器中要对返回状态进行判断
                    const token = store.state.token;        
                    token && (config.headers.Authorization = token);        
                    return config;    
                },    
                error => {        
                    return Promise.error(error);    
                })
            
            // 响应拦截器
            axios.interceptors.response.use(    
                response => {        
                    if (response.status === 200) {            
                        return Promise.resolve(response);        
                    } else {            
                        return Promise.reject(response);        
                    }    
                },
                // 服务器状态码不是200的情况    
                error => {        
                    if (error.response.status) {            
                        switch (error.response.status) {                
                            // 401: 未登录                
                            // 未登录则跳转登录页面，并携带当前页面的路径                
                            // 在登录成功后返回当前页面，这一步需要在登录页操作。                
                            case 401:                    
                                router.replace({                        
                                    path: '/login',                        
                                    query: { redirect: router.currentRoute.fullPath } 
                                });
                                break;
                            // 403 token过期                
                            // 登录过期对用户进行提示                
                            // 清除本地token和清空vuex中token对象                
                            // 跳转登录页面                
                            case 403:                     
                                Toast({                        
                                    message: '登录过期，请重新登录',                        
                                    duration: 1000,                        
                                    forbidClick: true                    
                                });                    
                                // 清除token                    
                                localStorage.removeItem('token');                    
                                store.commit('loginSuccess', null);                    
                                // 跳转登录页面，并将要浏览的页面fullPath传过去，登录成功后跳转需要访问的页面
                                setTimeout(() => {                        
                                    router.replace({                            
                                        path: '/login',                            
                                        query: { 
                                            redirect: router.currentRoute.fullPath 
                                        }                        
                                    });                    
                                }, 1000);                    
                                break; 
                            // 404请求不存在                
                            case 404:                    
                                Toast({                        
                                    message: '网络请求不存在',                        
                                    duration: 1500,                        
                                    forbidClick: true                    
                                });                    
                            break;                
                            // 其他错误，直接抛出错误提示                
                            default:                    
                                Toast({                        
                                    message: error.response.data.message,                        
                                    duration: 1500,                        
                                    forbidClick: true                    
                                });            
                        }            
                        return Promise.reject(error.response);        
                    }       
                }
            );
            /** 
             * get方法，对应get请求 
             * @param {String} url [请求的url地址] 
             * @param {Object} params [请求时携带的参数] 
             */
            export function get(url, params){    
                return new Promise((resolve, reject) =>{        
                    axios.get(url, {            
                        params: params        
                    })        
                    .then(res => {            
                        resolve(res.data);        
                    })        
                    .catch(err => {            
                        reject(err.data)        
                    })    
                });
            }
            /** 
             * post方法，对应post请求 
             * @param {String} url [请求的url地址] 
             * @param {Object} params [请求时携带的参数] 
             */
            export function post(url, params) {    
                return new Promise((resolve, reject) => {         
                    axios.post(url, QS.stringify(params))        
                    .then(res => {            
                        resolve(res.data);        
                    })        
                    .catch(err => {            
                        reject(err.data)        
                    })    
                });
            }

        // 或者
        // src/utils/request.js
        import axios from 'axios';
        import { Message, MessageBox } from 'element-ui'; // 以 Element UI 为例，可替换为其他 UI 库
        import store from '@/store'; // 引入 Vuex（用于 token 刷新等）
        import { getToken, removeToken } from '@/utils/auth'; // 自定义的 token 操作工具

        // 创建 axios 实例
        const service = axios.create({
        baseURL: process.env.VUE_APP_BASE_API || '/api', // 读取环境变量配置
        timeout: 15000, // 请求超时时间
        withCredentials: true // 允许携带 cookie
        });

        // 请求计数器（用于 loading 控制）
        let requestCount = 0;

        // 显示全局 loading（可选：使用 NProgress、Element Loading 等）
        function showLoading() {
        if (requestCount === 0) {
            // 例如：NProgress.start(); 或 Element Loading.service()
            // 这里用 Message.loading 模拟
            // 注意：实际项目中建议使用独立的 loading 组件
        }
        requestCount++;
        }

        function hideLoading() {
        requestCount--;
        if (requestCount <= 0) {
            requestCount = 0;
            // 例如：NProgress.done(); 或 loadingInstance.close()
        }
        }

        // 请求拦截器
        service.interceptors.request.use(
        config => {
            showLoading();

            // 添加 token 到请求头
            const token = getToken();
            if (token) {
            config.headers['Authorization'] = `Bearer ${token}`;
            }

            // 可添加其他通用头
            config.headers['Content-Type'] = 'application/json;charset=UTF-8';

            return config;
        },
        error => {
            hideLoading();
            console.error('[Request Error]:', error);
            return Promise.reject(error);
        }
        );

        // 响应拦截器
        service.interceptors.response.use(
        response => {
            hideLoading();

            const res = response.data;
            const status = response.status;

            // 业务成功状态码（假设后端约定 code === 0 为成功）
            if (res.code === 0 || res.code === 200 || res.success) {
            return res;
            }

            // ============ 业务状态码处理 ============
            const code = res.code;

            switch (code) {
            case 400:
                Message.error(res.message || '请求参数错误');
                break;

            case 401:
                // token 过期或无效
                MessageBox.confirm('登录已过期，请重新登录', '登录失效', {
                confirmButtonText: '重新登录',
                type: 'warning'
                }).then(() => {
                store.dispatch('user/resetToken').then(() => {
                    location.reload(); // 刷新页面
                });
                });
                break;

            case 403:
                Message.warning(res.message || '暂无权限');
                break;

            case 500:
                Message.error(res.message || '服务器内部错误');
                break;

            case 502:
            case 503:
            case 504:
                Message.error('网络异常，请稍后重试');
                break;

            default:
                if (res.message) {
                Message.error(res.message);
                } else {
                Message.error('未知错误，请联系管理员');
                }
            }

            return Promise.reject(new Error(res.message || 'Error'));
        },

        error => {
            hideLoading();

            const { response, message } = error;

            if (response) {
            // 服务器返回了状态码，但非 2xx
            const status = response.status;
            switch (status) {
                case 401:
                MessageBox.confirm('登录已过期，请重新登录', '登录失效', {
                    confirmButtonText: '重新登录',
                    type: 'warning'
                }).then(() => {
                    store.dispatch('user/resetToken').then(() => {
                    location.reload();
                    });
                });
                break;

                case 403:
                Message.error('拒绝访问');
                break;

                case 404:
                Message.error('请求资源不存在');
                break;

                case 500:
                Message.error('服务器内部错误');
                break;

                case 502:
                case 503:
                case 504:
                Message.error('网络连接异常');
                break;

                default:
                Message.error(`连接错误 ${status}`);
            }
            } else if (message.includes('timeout')) {
            Message.error('网络请求超时');
            } else if (message.includes('Network Error')) {
            Message.error('网络连接失败');
            } else {
            Message.error('未知网络错误');
            }

            return Promise.reject(error);
        }
        );

        // ============ 封装常用请求方法 ============
        export function get(url, params, config = {}) {
        return service({
            url,
            method: 'get',
            params,
            ...config
        });
        }

        export function post(url, data, config = {}) {
        return service({
            url,
            method: 'post',
            data,
            ...config
        });
        }

        export function put(url, data, config = {}) {
        return service({
            url,
            method: 'put',
            data,
            ...config
        });
        }

        export function del(url, params, config = {}) {
        return service({
            url,
            method: 'delete',
            params,
            ...config
        });
        }

        // 上传文件（form-data）
        export function upload(url, data, config = {}) {
        return service({
            url,
            method: 'post',
            data,
            headers: {
            'Content-Type': 'multipart/form-data'
            },
            timeout: 60000,
            ...config
        });
        }

        // 导出默认实例（用于特殊请求）
        export default service;
         * 
         * **/ 
    </script>
</body>
</html>